// 响应式
// const obj = {}

function defineReactive(obj, key, val) {
    // 递归  如果val 还是对象的话 进行遍历响应式
    observe(val)

    //对传入obj 进行访问拦截
    // 在每次执行defineReactive 时候，其实形成了一个闭包，因为在内部保留了一个内部作用域的变量 就是value
    Object.defineProperty(obj, key, {
        get() {
            console.log('get', key)
            return val;
        },
        set(newVal) {
            if (newVal !== val) {
                console.log('set::' + key + ":" + newVal)
                // 如果newVal 是对象，应该做响应化的处理
                observe(newVal)
                val = newVal
            }
        }
    })
}

function observe(obj) {
    if (typeof obj !== 'object' || obj == null) {
        // 希望传入的是obj
        return
    }
    // 遍历 相当于所有的可以 都定义了响应式
    Object.keys(obj).forEach(key => {
        defineReactive(obj, key, obj[key])
    })
}

function set(obj, key, val) {
    // 正常vue源码中是做了很多的判断，比如是否是需要响应化的数据
    defineReactive(obj, key, val)
}
// defineReactive(obj, 'foo', 'foo')
// obj.foo
// obj.foo = 'foooooooooooo'
const obj = {
    foo: 'foo',
    bar: 'bar',
    baz: {
        a: 1
    },
    arr: [1, 2, 3]
}
//遍历做响应化处理
observe(obj)
obj.foo
obj.foo = 'fooooooooooooooooooo'
obj.bar
obj.bar = 'barrrrrrrrrrrrrrrrrr'

// obj.baz.a = 10 //no ok 
// 设置newVal 是对象
obj.baz = {
    a: 100
}
obj.baz.a = 100000
// 以上给baz 新赋值了一个对象，也就是执行了对应的set 方法，但是新赋值的对象并没有执行defineReactive 方法，因此没有给每一个属性做响应式的处理
// 因此在set 方法中要多加一步处理 即 如果newVal 是一个对象的时候 要做一下响应化的处理 调用observe(val) 方法

// 增加或者删除一个属性  vue 中需要调用set 方法 因此实现一个set 方法
set(obj, 'dong', 'dong')
obj.dong
obj.dong = 'dongggggggggggggggggggg'

// obj 中有个数组 对数组的一些操作
// object.defineProperty() 对数组是无效的
// 解决思路：
// 分析 ：改变数组的方法只有7个，修改数组原型上响应的这7 个方法，进行覆盖。
// 解决方案：替换数组实例的原型方法，让她们在修改数组同时还可以通知更新
obj.arr.push(4)